package strangeattractor.core;

import java.awt.Point;

public abstract class StandardProjector implements Viewpoint {
	//The standard projector represents any projector with an angle and position.

	// theta-horizontal rotation
	// phi-vertical rotation
	private double theta = 0.25 * Math.PI, phi = 0;
	private int xShift = 100, yShift = 100;
	private double scaleX = 1, scaleY = 1;

	private double thetacos = Math.cos(theta);
	private double thetasin = Math.sin(theta);
	private double phicos = Math.cos(phi);
	private double phisin = Math.sin(phi);

	public void rotateHorizonal(double angle) {
		theta += angle;
		theta %= (2 * Math.PI);
		thetacos = Math.cos(theta);
		thetasin = Math.sin(theta);
	}

	public void rotateVertical(double angle) {
		phi += angle;
		phi %= (2 * Math.PI);
		phicos = Math.cos(phi);
		phisin = Math.sin(phi);
	}

	public void shift(int dx, int dy) {
		this.xShift += dx;
		this.yShift += dy;
	}

	@Override
	public Point getCoords(DPoint p) {
		Point sc = this.getStandardCoords(standardize(p), scaleX, scaleY);
		sc.x += xShift;
		sc.y += yShift;
		return sc;
	}

	@Override
	public double getZ(DPoint p) {
		return this.getStandardZ(standardize(p));
	}

	private DPoint standardize(DPoint p) {
		// FIXME
		double x1 = p.x * thetacos - p.z * thetasin;
		double z1 = p.z * thetacos + p.x * thetasin;

		double r = Math.sqrt(x1 * x1 + z1 * z1);

		double r2 = r * phicos + p.y * phisin;
		double y2 = p.y * phicos + r * phisin;

		double x2 = x1 * r2 / r;
		double z2 = z1 * r2 / r;

		return new DPoint(x2, y2, z2);
	}

	protected abstract Point getStandardCoords(DPoint p, double sx, double sy);

	protected abstract double getStandardZ(DPoint p);

	public void zoom(double factor) {
		this.scaleX += factor;
		this.scaleY += factor;
	}

}
